package restaurant;

import java.util.ArrayList;

import restaurant.iterators.ByCourseIterator;
import restaurant.iterators.ByPrepTimeIterator;
import restaurant.iterators.ByPriceIterator;
import restaurant.iterators.ByRatingIterator;
import restaurant.iterators.ByVegetarianIterator;
import restaurant.iterators.Iterator;
import restaurant.iterators.StandardIterator;

/**
 * Represents the menu of the restaurant. The {@code Menu} class is a collection
 * of {@code MenuItem} objects. In order to access a {@code MenuItem}, the
 * program must go through the {@code Menu} class.
 * 
 * @author Odessa
 * @see MenuItem
 */

public class Menu
{

	/** The list of menu items. */
	private ArrayList<MenuItem> menu;

	/** The menu item number. */
	private int itemNumber = 1;



	/**
	 * Instantiates the Menu.
	 */
	public Menu() {
		menu = new ArrayList<MenuItem>();
	}



	/**
	 * Creates a new menu item. The {@code itemNumber} is used so that each item
	 * created has a unique item number. After the item is created, it is added
	 * to the menu and the {@code itemNumber} gets incremented.
	 * 
	 * @param name the name of this item.
	 * @param description the description of this item.
	 * @param price the price of this item.
	 * @param prepTime the amount of time it takes to prepare this item.
	 * @param course this item's course.
	 * @param vegetarian whether or not this item is vegetarian.
	 * @return the newly created menu item.
	 */
	public MenuItem createItem(String name, String description, double price,
			int prepTime, String course, boolean vegetarian)
	{
		MenuItem m = new MenuItem(itemNumber, name, description, price,
				prepTime, course, vegetarian);
		add(m);
		itemNumber++;

		return m;
	}



	/**
	 * Updates a menu item. It first deletes the item from the menu. Once the
	 * item is deleted, a new menu item is created containing the new
	 * information passed to the method. Then, the newly created item is added
	 * to the menu.
	 * 
	 * @param itemNo the item number of the menu item to be updated.
	 * @param name the name of this item.
	 * @param description the description of this item.
	 * @param price the price of this item.
	 * @param prepTime the amount of time it takes to prepare this item.
	 * @param course this item's course.
	 * @param vegetarian whether or not this item is vegetarian.
	 * @return the updated menu item.
	 */
	public MenuItem updateItem(int itemNo, String name, String description,
			double price, int prepTime, String course, boolean vegetarian)
	{
		delete(itemNo);
		MenuItem m = new MenuItem(itemNo, name, description, price, prepTime,
				course, vegetarian);
		add(m);

		return m;
	}



	/**
	 * Adds the {@code item} to the menu. Takes a menu item and appends it to
	 * the end of the menu ArrayList.
	 * 
	 * @param item the item to be added to the menu.
	 */
	public void add(MenuItem item)
	{
		menu.add(item);
	}



	/**
	 * Deletes an item from the menu. It first finds the item in the menu and
	 * then deletes it.
	 * 
	 * @param itemNo the item number of the item to be deleted.
	 */
	public void delete(int itemNo)
	{
		MenuItem item = find(itemNo);
		menu.remove(item);
	}



	/**
	 * Sets the number of an item that is available. It first finds the item in
	 * the menu and then sets the number available.
	 * 
	 * @param itemNo the item number of the menu item to set the number
	 *            available for.
	 * @param numAvailable the number available of the item.
	 */
	public void setItemAvailability(int itemNo, int numAvailable)
	{
		MenuItem item = find(itemNo);
		item.setNumAvailable(numAvailable);
	}



	/**
	 * Sets the rating of an item. It first finds the item in the menu and then
	 * sets the rating.
	 * 
	 * @param itemNo the item number of the menu item to set the rating for.
	 * @param rating the rating of the item.
	 */
	public void setItemRating(int itemNo, double rating)
	{
		MenuItem item = find(itemNo);
		item.setRating(rating);
	}



	/**
	 * Finds the item in the menu. It looks at all the items in the menu and
	 * returns the item with the specified item number.
	 * 
	 * @param itemNo the item number of the item to find.
	 * @return the menu item matching the item number entered.
	 */
	private MenuItem find(int itemNo)
	{
		MenuItem item = null;

		for (MenuItem m : menu) {
			int id = m.getItemNo();

			if (id == itemNo) {
				item = m;
				break;
			}
		}

		return item;
	}



	/**
	 * Gets the standard iterator. Since the {@code StandardIterator} takes an
	 * ArrayList of Objects, the menu is first converted into the correct
	 * format. Then it creates a new iterator and returns it. The standard
	 * iterator is used to iterate through the entire menu.
	 * 
	 * @return the standard iterator.
	 * @see StandardIterator
	 */
	public Iterator getStandardIterator()
	{
		ArrayList<Object> list = new ArrayList<Object>();

		for (MenuItem m : menu)
			list.add(m);

		return new StandardIterator(list);
	}



	/**
	 * Gets an iterator of type {@code ByPriceIterator}. It creates a new
	 * iterator and returns it.
	 * 
	 * @param price the price by which to view the menu.
	 * @return the iterator to view the menu by price.
	 * @see ByPriceIterator
	 */
	public Iterator getByPriceIterator(double price)
	{
		return new ByPriceIterator(menu, price);
	}



	/**
	 * Gets an iterator of type {@code ByPrepTimeIterator}. It creates a new
	 * iterator and returns it.
	 * 
	 * @param time the preparation time by which to view the menu.
	 * @return the iterator to view the menu by preparation times.
	 * @see ByPrepTimeIterator
	 */
	public Iterator getByPrepTimeIterator(int time)
	{
		return new ByPrepTimeIterator(menu, time);
	}



	/**
	 * Gets an iterator of type {@code ByRatingIterator}. It creates a new
	 * iterator and returns it.
	 * 
	 * @param rating the item rating by which to view the menu.
	 * @return the iterator to view the menu by item ratings.
	 * @see ByRatingIterator
	 */
	public Iterator getByRatingIterator(int rating)
	{
		return new ByRatingIterator(menu, rating);
	}



	/**
	 * Gets an iterator of type {@code ByCourseIterator}. It creates a new
	 * iterator and returns it.
	 * 
	 * @param course the course by which to view the menu.
	 * @return the iterator to view the menu by course.
	 * @see ByCourseIterator
	 */
	public Iterator getByCourseIterator(String course)
	{
		return new ByCourseIterator(menu, course);
	}



	/**
	 * Gets an iterator of type {@code ByVegetarianIterator}. It creates a new
	 * iterator and returns it.
	 * 
	 * @return the iterator to view only vegetarian dishes.
	 * @see ByVegetarianIterator
	 */
	public Iterator getByVegetarianIterator()
	{
		return new ByVegetarianIterator(menu);
	}

}
